class LineBreakTransformer2 {
    constructor() {
        this.container = '';
    }

    transform(chunk, controller) {
        this.container += chunk;
        const lines = this.container.split('\r\n');
        this.container = lines.pop();
        lines.forEach(line => controller.enqueue(line));
    }

    flush(controller) {
        controller.enqueue(this.container);
    }
}


async function readDataLoop(port, controller, onNewData) {
    // const controller = new AbortController();
    const signal = controller.signal;
    // let port = await navigator.serial.requestPort();
    await port.open({ baudRate: 115200 }); // set baud rate
    console.log(port)
    keepReading = true;
    const textDecoder = new TextDecoderStream();
    const lineBreaker = new TransformStream(new LineBreakTransformer2())
    textDecoderClosed = port.readable.pipeTo(textDecoder.writable, { signal })
    lineBreakerClosed = textDecoder.readable.pipeTo(lineBreaker.writable, { signal })
    let reader = lineBreaker.readable.getReader();
    // writer = port.writable.getWriter();

    // set how to write to device intervally
    // const writeInt = setInterval(async () => {
    //   const commandframe = new Uint8Array([
    //     0x00,
    //     0xff,
    //     /*...some bytes to be sent*/
    //   ]);
    //   await writer.write(commandframe);
    // }, 3000); // send a frame every 3000ms

    while (port.readable && keepReading) {
        try {
            while (keepReading) {
                const { value, done } = await reader.read();
                if (done) {
                    // Allow the serial port to be closed later.
                    reader.releaseLock();
                    // Allow the serial port to be closed later.
                    // writer.releaseLock();
                    break;
                }
                if (value) {
                    /*** TODO: deal with the data value ***/
                    let line = value.split(': ')
                    if (line.length == 2) {
                        let prefix = line[0]
                        let data = line[1].split(',').map(Number)
                        // console.log(prefix, data)
                        data.shift()
                        let value = null
                        if (prefix.startsWith('SPECT')) {
                            let keys = ['F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'CLE', 'NIR']
                            value = {}
                            for (let i = 0; i < keys.length; i++) {
                                value[keys[i]] = data[i]
                            }
                        } else if (prefix.startsWith('INFRA')) {
                            value = { 'env': data[0], 'measure': data[1] }
                        } else if (['FORCE', 'TEMPE', 'VOLTA', 'ECURR', 'MVOLT', 'MCURR', 'SOUND'].indexOf(prefix) >= 0) {
                            value = {}
                            value[prefix] = data
                        }
                        if (value) {
                            setupOrUpdate(value, colors2)
                        }
                        onNewData()
                    }
                }
            }
        } catch (error) {
            // Handle non-fatal read error.
            console.error(error);
            keepReading = false
        } finally {
            console.log(port.readable, keepReading);
        }
    }

    try {
        // Allow the serial port to be closed later.
        reader.releaseLock();
        controller.abort('manually disconnected')

    } catch (error) {
        console.log(error)
    }
    try {
        await textDecoderClosed;
        await lineBreakerClosed;
    } catch (error) {
        console.log(error)
    }

    await port.close();

    // clearInterval(writeInt);
    console.log("port closed", reader, textDecoder, lineBreaker);

}

async function disconnect() {

    // reader.cancel();
    // await port.close();
}

let sensorState = {

}

let sensorNameMap = {

}



async function detectSensorType(port, index, onNewSensor) {
    let keepReading = true;

    const nameMap = {
        'FORCE': '力传感器',
        'TEMPE': '热电偶温度传感器',
        'VOLTA': '电压传感器',
        'ECURR': '电流传感器',
        'SOUND': '声音传感器',
        'SPECT': '光谱传感器',
        'INFRA': '红外温度传感器',
        'MVOLT': '微电压传感器',
        'MCURR': '微电流传感器',
    }

    const controller = new AbortController();
    const signal = controller.signal;
    await port.open({ baudRate: 115200 }); // set baud rate
    console.log(port)
    const textDecoder = new TextDecoderStream();
    const lineBreaker = new TransformStream(new LineBreakTransformer2())
    let textDecoderClosed = port.readable.pipeTo(textDecoder.writable, { signal })
    let lineBreakerClosed = textDecoder.readable.pipeTo(lineBreaker.writable, { signal })
    let reader = lineBreaker.readable.getReader();
    while (port.readable && keepReading) {
        try {
            while (keepReading) {
                const { value, done } = await reader.read();
                if (done) {
                    // Allow the serial port to be closed later.
                    reader.releaseLock();
                    // Allow the serial port to be closed later.
                    // writer.releaseLock();
                    break;
                }
                if (value) {
                    /*** TODO: deal with the data value ***/
                    let line = value.split(': ')
                    // console.log(value, line)
                    if (line.length == 2) {
                        let prefix = line[0].trim()
                        let data = line[1].split(',').map(Number)
                        // console.log(prefix, data, ['FORCE', 'TEMPE', 'VOLTA', 'ECURR', 'MVOLT', 'MCURR', 'SOUND'].indexOf(prefix))
                        data.shift()
                        let value = null
                        if (prefix.startsWith('SPECT')) {
                            let keys = ['F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'CLE', 'NIR']
                            value = {}
                            for (let i = 0; i < keys.length; i++) {
                                value[keys[i]] = data[i]
                            }
                        } else if (prefix.startsWith('INFRA')) {
                            value = { 'env': data[0], 'measure': data[1] }
                        } else if (['FORCE', 'TEMPE', 'VOLTA', 'ECURR', 'MVOLT', 'MCURR', 'SOUND'].indexOf(prefix) >= 0) {
                            value = {}
                            value[prefix] = data
                        }
                        if (value) {
                            sensorState[index].value = value
                            sensorState[index].raw_data = data
                            sensorState[index].updated = true
                            if (sensorState[index].type.length == 0) {
                                sensorState[index].sensor_id = prefix.trim() + index
                                let type = prefix.trim()
                                sensorState[index].type = type
                                let count = Object.keys(sensorNameMap).filter(key => key.startsWith(nameMap[type])).length
                                if (count >= 1) {
                                    sensorState[index].sensor_name = `${nameMap[type]}-${count + 1}`
                                } else {
                                    sensorState[index].sensor_name = `${nameMap[type]}`
                                }
                                sensorNameMap[sensorState[index].sensor_name] = index
                                onNewSensor(sensorState[index].sensor_name, index)
                            }
                            keepReading = false
                            // if (prefix.startsWith('SOUND')) {
                            //     sensorState[index].buffer.push(data)
                            //     if (sensorState[index].buffer.length > 32) {
                            //         sensorState[index].buffer = sensorState[index].buffer.slice(sensorState[index].buffer.length - 16)
                            //     }
                            // }
                        }
                    }
                }
            }
        } catch (error) {
            // Handle non-fatal read error.
            console.error(error);
        } finally {
            console.log(port.readable, keepReading);
        }
    }

    try {
        // Allow the serial port to be closed later.
        reader.releaseLock();
        controller.abort('manually disconnected')

    } catch (error) {
        console.log(error)
    }
    try {
        await textDecoderClosed;
        await lineBreakerClosed;
    } catch (error) {
        console.log(error)
    }

    await port.close();

    // clearInterval(writeInt);
    console.log("port closed", reader, textDecoder, lineBreaker);
}

async function connectSensors(onNewSensor) {
    sensorState = {}
    sensorNameMap = {}
    let ports = await navigator.serial.getPorts()
    for (let index = 0; index < ports.length; index++) {
        const port = ports[index];
        if (port.getInfo().usbVendorId == 12346) {
            sensorState[index + 1] = {
                type: '',
                sensor_name: '',
                value: '',
                raw_data: [],
                buffer: [],
                port: port,
                updated: false
            }
            detectSensorType(port, index + 1, onNewSensor)
        }
    }
}